#include "font_manager.h"
#include "font.h"
#include "bitmap_font.h"
#include "graphics/graphics.h"
#include "script/file_list.h"

#include "util/common_macros.h"		// macros
#include "util/log.h"		// macros
#include "util/mmgr.h"		// Needs to come in early

#include "num/crc32.h"

#include <stdarg.h>
#include <cassert>


FontManager::FontManager( ) : 
    m_pDefaultFont(NULL)
{

}

FontManager::~FontManager()
{
	Shutdown();
}

FontManager&   FontManager::Instance()
{
    static FontManager Inst;
    return Inst;
}

static void		AddFontToSet(Font* pFont, void* pData)
{
	std::vector<Font*>* pSet = (std::vector<Font*>*)pData;
	pSet->push_back(pFont);
}

void			FontManager::GetFonts(std::vector<Font*>& Set)
{
	ForEach(AddFontToSet, &Set);
}

bool			FontManager::Shutdown()
{
    m_pDefaultFont = NULL;  // gets deleted with the other stored pointers
	ClearSet();
#ifdef _PLATFORM_WIN32
	script::FileList		List;
	List.Build("fonts/*.ttf");
	for (int i=0; i<List.GetFileC(); i++)
	{
		RemoveFontResource(List.GetFileName(i).c_str());	
	}
#endif //_PLATFORM_WIN32	
	return true;
}

void		FontManager::Flush()
{
	for (ElementMap::iterator It = m_Set.begin(); It != m_Set.end(); It++)
	{
		It->second->Flush();
	}
}

void		FontManager::Recreate()
{
	// there's no default font == not initialized yet
	if (m_pDefaultFont)
	{
		for (ElementMap::iterator It = m_Set.begin(); It != m_Set.end(); It++)
		{
			It->second->Recreate();
		}
	}
}



bool		FontManager::Init(   const std::string&  _DefaultFont,
                        int                 _DefaultHeight,
                        int                 _DefaultWidth,
                        int                 _DefaultFlags)
{
	// init any fonts in the fonts/ directory
#ifdef _PLATFORM_WIN32
	script::FileList		List;
	List.Build("fonts/*.ttf");
	for (int i=0; i<List.GetFileC(); i++)
	{
		AddFontResource(List.GetFileName(i).c_str());	
	}
#endif //_PLATFORM_WIN32
	m_pDefaultFont = InitFont("Default", _DefaultFont, _DefaultHeight, _DefaultWidth, false, 500, 0);
	return true;
}

Font*        FontManager::InitFont( 
							const std::string& _FontName,
                             const std::string& _Face,
                             unsigned long      _Width,
                             unsigned long      _Height,
							 bool				_Italic,
							 int				Weight, 
							 unsigned long	CharSet )
{   
	if (_FontName.empty()) return NULL;
	if (_Face.empty()) return NULL;

	Font* pFont = GetElement(_FontName);
	if (pFont)
		return pFont;	// already exists

	
	pFont = GetGraphics()->CreateTTFFont(_FontName);
	
	if(pFont)
	{
		pFont->Resize(_Face, _Width, _Height, Weight, CharSet);
		AddElement(_FontName, pFont);
	}
	return pFont;
	
/*}
	return m_pDefaultFont;*/
}

Font*  FontManager::InitBitmapFont( const std::string& _FontName, const std::string& _File)
{
	Font* pFont = GetElement(_FontName);
	if (pFont)
		return pFont;	// already exists

	pFont = new BitmapFont(_FontName);
	pFont->Init(_File, 0, 0, 0, 0);
	AddElement(_FontName, pFont);
	return pFont;
}




void   FontManager::PrintCentered(const math::Vec2& _Pos, const char*  _Msg, ...)
{
    PrintCached     Element;
    Font*        pDefault = GetDefaultFont();

	// Concatanate the message into a single buffer
	char Message[1024];
	va_list ArgP;
	va_start(ArgP, _Msg);
	vsprintf(Message, _Msg, ArgP);
	va_end(ArgP);

    Element.Pos    = _Pos;
    Element.Text   = Message;
    Element.pFont  = NULL; //_pFont;
	Element.Color  = m_DefaultColor;

	if (pDefault)
	{
		math::Vec2	From, Size;
		pDefault->GetTextExtent(Message, math::Vec2(1,1), From, Size);
		Element.Pos    = _Pos - (Size*0.5f);
	}

    Instance().m_PrintCache.push_back(Element);
}

void   FontManager::PrintCentered(Font* pUseFont, const math::Vec2& _Pos, const char*  _Msg, ...)
{
    PrintCached     Element;
    Font*			pDefault = pUseFont;
	if (!pDefault)	pDefault = GetDefaultFont();

	// Concatanate the message into a single buffer
	char Message[1024];
	va_list ArgP;
	va_start(ArgP, _Msg);
	vsprintf(Message, _Msg, ArgP);
	va_end(ArgP);

    Element.Pos    = _Pos;
    Element.Text   = Message;
    Element.pFont  = pDefault;
	Element.Color  = m_DefaultColor;

	if (pDefault)
	{
		math::Vec2	From, Size;
		pDefault->GetTextExtent(Message, math::Vec2(1,1), From, Size);
		Element.Pos    = _Pos - (Size*0.5f);
	}

    Instance().m_PrintCache.push_back(Element);
}


void   FontManager::Print(const math::Vec2& _Pos, const char*  _Msg, ...)
{
    PrintCached     Element;

	// Concatanate the message into a single buffer
	char Message[1024];
	va_list ArgP;
	va_start(ArgP, _Msg);
	vsprintf(Message, _Msg, ArgP);
	va_end(ArgP);

    Element.Pos    = _Pos;
    Element.Text   = Message;
    Element.pFont  = NULL; //_pFont;
	Element.Color  = m_DefaultColor;

    Instance().m_PrintCache.push_back(Element);
}

void   FontManager::Print(Font* pUseFont, const math::Vec2& _Pos, const char*  _Msg, ...)
{
    PrintCached     Element;

	// Concatanate the message into a single buffer
	char Message[1024];
	va_list ArgP;
	va_start(ArgP, _Msg);
	vsprintf(Message, _Msg, ArgP);
	va_end(ArgP);

    Element.Pos    = _Pos;
    Element.Text   = Message;
    Element.pFont  = pUseFont;
	Element.Color  = m_DefaultColor;

    Instance().m_PrintCache.push_back(Element);
}

void  FontManager::RenderCache()
{
	//GetGraphics()->Start2D();

    Font*        pDefault = GetDefaultFont();
	if (!pDefault)
	{
		_LOG(MSG_WARNING, "Invalid default font!");
		if (GetElementC() == 0)
		{
			_LOG(MSG_WARNING, "No valid fonts!!");
			return;
		}
		m_pDefaultFont = GetElement("SmallFont");
		if (!m_pDefaultFont)
			m_pDefaultFont = GetElementByIndex(0);

		pDefault = GetDefaultFont();
		if (!pDefault) // okay, I give up
			return;
	}
	for (unsigned int i=0; i<m_PrintCache.size(); i++)
    {
        PrintCached&     Element = m_PrintCache[i];
        if (!Element.pFont)
            Element.pFont = pDefault;
        assert(Element.pFont);
		Element.pFont->Render(Element.Text, Element.Pos, math::Vec2(1, 1), 0, Element.Color);
    }
    m_PrintCache.resize(0);
	m_DefaultColor = ColorRGBA(255, 255, 255); 

	if (pDefault)
		pDefault->FlushSprite();
}
